
#include "common.h"
#include "ConfigManager.h"
#include "LogUtil.h"

#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cassert>
#include <cstring>
#include <string>

using namespace std;

__BEGIN_NAMESPACE_DECL_

// static member variable definitions
ConfigManager *ConfigManager::_manager = NULL;

// static member function definitions
ConfigManager&
ConfigManager::getInstance()
{
    if (_manager == NULL)
        _manager = new ConfigManager();

    return *_manager;
}

// Empty constructor
ConfigManager::ConfigManager()
{
}

// getProperty
const char *
ConfigManager::getProperty(const char *property, const char *defaultValue)
{
    assert (property != NULL);
    std::string propName = property;
    std::map<std::string, std::string>::iterator iter;

    iter = _propertyMap.find(propName);
    if (iter != _propertyMap.end())
        return iter->second.c_str();

    return defaultValue;
}

const char *
ConfigManager::getProperty(const char *property)
{
    return this->getProperty (property, NULL);
}

// setProperty
bool
ConfigManager::setProperty(const char *property, const char *value)
{
    assert (property != NULL);
    assert (value != NULL);
    std::string propName = property;
    std::string propValue = value;
    bool retval = false;

    std::map<std::string, std::string>::iterator iter;
    
    // return true if we are replacing the value for an element
    // that already exists.
    iter = _propertyMap.find(propName);
    if (iter != _propertyMap.end())
        retval = true;

    // assign the new/updated value to reference returned by []
    _propertyMap[propName] = propValue;

    return retval;
}

// exists
bool
ConfigManager::exists (const char *property) const
{
    assert (property != NULL);
    std::string propName = property;
    std::map<std::string, std::string>::const_iterator iter;

    iter = _propertyMap.find(propName);
    if (iter != _propertyMap.end())
        return true;

    return false;
}

// clear
void
ConfigManager::clear()
{
    _propertyMap.clear();
}

// loadPropertiesFromFile
bool
ConfigManager::loadPropertiesFromFile (const char *filename)
{
    assert (filename != NULL);
    FILE *fp;
#define MAXLINESZ 1024
    char line[MAXLINESZ];
    char property[MAXLINESZ];
    char value[MAXLINESZ];
    int linenum;
    
    if ((fp = fopen(filename, "r")) == NULL)
    {
        WARN << "Unable to open file \"" << filename << "\": "
             << strerror(errno);
        return false;
    }

    linenum = 1;
    while (fgets(line, MAXLINESZ, fp) != NULL)
    {
        int i, j;

        // get rid of newline
        if (line[strlen(line)-1] == '\n')
            line[strlen(line)-1] = '\0';
        if (line[strlen(line)-1] == '\r')
            line[strlen(line)-1] = '\0';

        // skip blank lines or lines starting with #
        if (line[0] == '\0' || line[0] == '#')
            continue;

        // copy all characters up to the equal sign into the property name
        for (i=0; line[i] != '\0' && line[i] != '='; i++)
            property[i] = line[i];
        property[i] = '\0';

        // if we aren't at the equal sign, then this is a malformed line
        if (line[i++] != '=')
        {
            WARN << "Malformed line, missing equals sign: line " << line;
            continue;
        }

        // copy remaining characters into value
        for (j=0; line[i] != '\0'; i++, j++)
            value[j] = line[i];
        value[j] = '\0';

        // Now we have a property and value, set it in the map.
        DEBUG << property << "=" << value;
        setProperty (property, value);

        // increment count of lines
        linenum++;
    }
    
    fclose(fp);

    return true;
}

// listProperties
void
ConfigManager::listProperties()
{
    std::map<std::string, std::string>::iterator iter;

    std::cout << "Printing configuration properties..." << std::endl;
    for (iter=_propertyMap.begin(); iter != _propertyMap.end(); ++iter)
    {
        std::cout << iter->first << "=" << iter->second << std::endl;
    }
}



__END_NAMESPACE_DECL_
